package org.summerframework.component.security.core.service.impl;

import org.summerframework.component.security.Constants;
import org.summerframework.component.security.LoginData;
import org.summerframework.component.security.core.SecurityResultCode;
import org.summerframework.component.security.core.config.LoginProperties;
import org.summerframework.component.security.core.service.ThirdPartyLoginService;
import org.summerframework.component.security.oauth.Info;
import org.summerframework.component.security.oauth.LoginType;
import org.summerframework.component.security.oauth.OAuthUserInfoInterceptor;
import org.summerframework.core.base.result.DefaultResultCode;
import org.summerframework.core.exception.AppException;
import org.summerframework.core.exception.WebException;
import org.summerframework.core.util.CheckUtil;
import org.summerframework.core.util.UrlEncodeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.ServletRequestUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 第三方登录抽象类
 * <p>
 * 接收参数
 * 默认参数:{@link AbstractLoginServiceImpl}
 * code: OAuth 拓展信息
 * {@link #getParamCode()}更新改获取参数的名称
 * <p>
 * isBind: true绑定快捷登录, 需要要登录  false正常登录  默认false
 *
 * @param <T> {@link Info}
 * @author 石超
 * @version v1.0.0
 */
public abstract class AbstractThirdPartyLoginServiceImpl<T, I extends Info> extends AbstractLoginServiceImpl<T> implements ThirdPartyLoginService<T, I> {
    @Resource
    private OAuthUserInfoInterceptor oAuthUserInfoInterceptor;

    @Resource
    private LoginProperties loginProperties;

    @Override
    protected T validateLoginContext() {
        LoginData<T> loginData = getLoginData();
        HttpServletRequest request = getContext().getRequest();

        try {
            String code = ServletRequestUtils.getStringParameter(request, getParamCode(), "");

            if (StringUtils.isBlank(code)) {
                throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT);
            }

            I info = oAuthUserInfoInterceptor.getOAuthUserInfo(code, UrlEncodeUtil.encodeURL(loginData.getRedirectUrl()), LoginType.valueOf(loginProperties.getOauth().get(loginData.getLoginType())));


            if (isBind()) {
                //loginData.setJson(1);

                if (!getContext().getLoginData().isLogin()) {
                    throw new WebException(SecurityResultCode.ERROR_NOT_LOGIN);
                }
                synchronized (getContext().getLoginData().getUserId()) {
                    doBind(info, getContext().getLoginData());
                }

                return null;
            } else {
                return validateLoginContext(info);
            }
        } catch (AppException e) {
            throw e;
        } catch (Exception e) {
            throw new WebException(DefaultResultCode.SYSTEM_ERROR, e);
        } finally {
            setRedirectUrl();
        }
    }

    @Override
    public void finishLogin() {
        if (!isBind()) {
            super.finishLogin();
        } else {
            validateLoginContext();
        }
    }

    void setRedirectUrl() {
        if (StringUtils.isNotBlank(redirectUrl())) {
            String redirectUrl = ServletRequestUtils.getStringParameter(getContext().getRequest(), redirectUrl(), "");

            if (StringUtils.isNotBlank(redirectUrl) && CheckUtil.isUrl(redirectUrl)) {
                getLoginData().setRedirectUrl(redirectUrl);
            }
        }
    }

    public boolean isBind() {
        return ServletRequestUtils.getBooleanParameter(getContext().getRequest(), "isBind", false);
    }

    protected abstract void doBind(I t, LoginData<T> loginData);

    @Override
    public T validateLoginContext(I t) {
        throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT);
    }

    @Override
    protected boolean hasUsername() {
        return false;
    }

    String redirectUrl() {
        return null;
    }

    String getParamCode() {
        return Constants.DYNAMIC_CODE;
    }
}
